#include <webx/route.h>

class Compile : public webx::ProcessBase
{
protected:
	int process();
};

HTTP_WEBAPP(Compile, "/compile/${filename}")

int Compile::process()
{
	TaskQueue* queue = TaskQueue::Instance();
	string path = app->getPath() + "app/compile/cpp/";

	if ((queue->size() << 1) >= queue->getThreads())
	{
		Sleep(100);

		return simpleResponse(XG_SYSBUSY);
	}

	time_t now = time(NULL);
	vector<string> pathlist;

	pathlist.push_back(path);
	pathlist.push_back(path + ".bin/");

	for (auto path : pathlist)
	{
		time_t utime;
		vector<string> vec;

		if (stdx::GetFolderContent(vec, path, eFILE) < 100) break;

		for (string& name : vec)
		{
			if (name == "config.lua" || name == "config.cpp") continue;

			name = path + name;
			utime = path::mtime(name);
	
			if (utime + 300 < now)
			{
				LogTrace(eINF, "file[%s][%s] has expired", name.c_str(), DateTime(utime).toString().c_str());
	
				path::remove(name);
			}
		}
	}

	param_string(code);
	param_string(param);

	param = stdx::trim(param);

	webx::CheckFilePath(param, 0, 1024);

	if (code.empty() || code.length() > 256 * 1024) return simpleResponse(XG_PARAMERR);

	char buffer[64 * 1024];
	string filename = path;

	stCharBuffer name = MD5GetEncodeString(code.c_str(), code.length(), true);

	stdx::append(filename, "%s.cpp", name.val);

	if (path::size(filename) > 0)
	{
		Sleep(100);
	}
	else
	{
		File file;
		size_t pos;
		size_t end;

		code = stdx::replace(code, "\r", "");
		pos = code.find("\n\n");
		end = code.find("{");
		
		if (pos == string::npos || pos > end)
		{
			code = "#include \"config.cpp\"\n" + code;
		}
		else
		{
			code = code.substr(0, pos) + "\n#include \"config.cpp\"" + code.substr(pos + 1);
		}

		file.open(filename , "w+");

		if (file.getHandle() == NULL) return simpleResponse(XG_SYSERR);

		if (file.write(code.c_str(), code.length()) <= 0) return simpleResponse(XG_SYSERR);
	}

	string output;
	string errpath = path;

	stdx::append(errpath, "%s.out", name.val);

#ifdef XG_LINUX
	string exepath = stdx::translate("$PRODUCT_HOME/bin/cppshell");

	stdx::format(code, "ulimit -c 0 && %s %s %s 2>%s", stdx::quote(exepath).c_str(), stdx::quote(filename).c_str(), param.c_str(), stdx::quote(errpath).c_str());
#else
	string exepath = stdx::translate("$PRODUCT_HOME/bin/cppshell.exe");

	stdx::format(code, "%s %s %s 2>%s", stdx::quote(exepath).c_str(), stdx::quote(filename).c_str(), param.c_str(), stdx::quote(errpath).c_str());
#endif
	if (cmdx::RunCommand(code, buffer, sizeof(buffer), true, false) < 0) return simpleResponse(XG_SYSERR);

	stdx::GetFileContent(output, errpath);

	output = stdx::trim(output);

	auto getTranslateString = [&](string output){
		output = stdx::replace(output, "&", "&amp;");
		output = stdx::replace(output, ">", "&gt;");
		output = stdx::replace(output, "<", "&lt;");
		output = stdx::replace(output, "\"", "&quot;");
		output = stdx::replace(output, filename, "code.cpp");
		return stdx::replace(output, path::name(filename), "code.cpp");
	};

	if (output.empty())
	{
		output = getTranslateString(buffer);
		output = "<font>" + output + "</font>";
		output = stdx::replace(output, "\e[31m", "</font><font color='#BB0000'>");
		output = stdx::replace(output, "\e[32m", "</font><font color='#00BB00'>");
		output = stdx::replace(output, "\e[33m", "</font><font color='#BBBB00'>");
		output = stdx::replace(output, "\e[34m", "</font><font color='#0000BB'>");
		output = stdx::replace(output, "\e[37m", "</font><font color='#888888'>");

		json["code"] = XG_OK;
	}
	else
	{
		if (output.find("SYSTEM ERROR[-5]") == string::npos)
		{
			output = getTranslateString(output);

			json["code"] = XG_PARAMERR;
		}
		else
		{
			json["code"] = XG_TIMEOUT;

			output.clear();
		}
	}

	json["output"] = output;

	out << json;

	return XG_OK;
}